package com.espirit.eap.manager;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.apache.struts2.dispatcher.ServletActionRedirectResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.espirit.common.RelatedFile;
import com.espirit.common.UploadFileService;
import com.espirit.eap.conversion.BigDecimalConverter;
import com.espirit.eap.pagelayout.ModelService;
import com.espirit.eap.pagelayout.UrlUtil;
import com.espirit.eap.util.Functions;
import com.googlecode.cswish.Config;
import com.googlecode.cswish.annotation.ParamScope;
import com.googlecode.cswish.model.PageElements;
import com.googlecode.cswish.struts.conversion.DefaultDateConverter;
import com.googlecode.cswish.struts.spring.BeanIntrospector;
import com.googlecode.cswish.struts.spring.CacheService;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.googlecode.cswish.util.BlankObject;
import com.googlecode.cswish.util.OgnlExUtil;
import com.googlecode.cswish.util.bean.ModelUtil;
import com.opensymphony.xwork2.Result;

@Service
public class SystemSettingService {

	private final static Logger logger = Logger.getLogger(SystemSettingService.class);
	
	@Resource
	private GenericService genericService;
	
	@Resource
	private ObjectFactory objectFactory;
	
	@Resource
	private Config config;
	
	@Resource
	private I18nService i18nService;
	
	@Resource
	BeanIntrospector beanIntrospector;
	
	@Resource
	private UploadFileService uploadFileService;
	
	@Resource
	UrlUtil urlUtil;
	
	@Resource
	ModelService modelService;
	
	@Resource
	Functions functions;
	
	@Resource
	SystemDataService systemDataService;
	
	@Resource
	CacheService cacheService;
	
	@Resource
	OgnlExUtil ognlExUtil;
	
	@Resource
	private DefaultDateConverter defaultDateConverter;
	
	@Resource
	private BigDecimalConverter bigDecimalConverter;
	
	Map<String ,String> globalSettingCache ;
	Map<String, SystemSetting> systemSettingCache;
	
	@PostConstruct
	private void init() {
		globalSettingCache = cacheService.newCache(String.class);
		systemSettingCache = cacheService.newCache(SystemSetting.class);
	}
	
	private String getValue(String key, String defaultValue){
		String value = globalSettingCache.get(key);
		if (value == null ){
			String dataValue = systemDataService.getValue(key);
			if (dataValue == null){
				int pos = key.indexOf(".");
				Object val = functions.val(getSystemSetting().safeGlobalSetting(), key.substring(pos + 1));
				if (val != null){
					value = val.toString();
				} else {
					value = defaultValue;
				}
				setValue(key, value);
			} else {
				value = dataValue;
			}
			if (value != null){
				globalSettingCache.put(key, value);
			}
		}
		return value;
	}
	
	public void setValue(String key, String value){
		systemDataService.setValue(key, value);
	}
	
	public Integer getPriceScale(){
		String value = getValue(GlobalSetting.PRICE_SCALE, "2");
		return Integer.valueOf(value);
	}
	
	void setPriceScale(Integer priceScale){
		if (priceScale == null){
			priceScale = 2;
		}
		setValue(GlobalSetting.PRICE_SCALE, priceScale.toString());
		
		bigDecimalConverter.setPriceScale(priceScale);
	}
	
	public Integer getAmountScale() {
		String value = getValue(GlobalSetting.AMOUNT_SCALE, "2");
		return Integer.valueOf(value);
	}
	
	void setAmountScale(Integer amountScale){
		if (amountScale == null){
			amountScale = 2;
		}
		setValue(GlobalSetting.AMOUNT_SCALE, amountScale.toString());
		
		bigDecimalConverter.setAmountScale(amountScale);
	}

	public Boolean getAutoGoNext(){
		String value = getValue(GlobalSetting.AUTO_GONEXT, Boolean.FALSE.toString());
		return Boolean.valueOf(value);
	}
	
	void setAutoGoNext(Boolean autoGoNext){
		if (autoGoNext == null){
			autoGoNext = Boolean.FALSE;
		}
		setValue(GlobalSetting.AUTO_GONEXT, autoGoNext.toString());
	}
	
	public String getDateFormat(){
		String value = getValue(GlobalSetting.DATE_FORMAT, config.getDataFormat());
		return value;
	}
	
	void setDateFormat(String dateFormat){
		if (dateFormat == null){
			dateFormat = config.getDataFormat();
		}
		setValue(GlobalSetting.DATE_FORMAT, dateFormat);
		
		defaultDateConverter.setDateFormat(dateFormat);
	}
	
	public Integer getPageSize(){
		String value = getValue(GlobalSetting.PAGE_SIZE, "30");
		Integer pageSize = Integer.valueOf(value);
		if (pageSize > 1000){
			pageSize = 30;
		}
		return pageSize;
	}
	void setPageSize(Integer pageSize){
		if (pageSize == null){
			pageSize = 30;
		}
		setValue(GlobalSetting.PAGE_SIZE, pageSize.toString());
	}
	
	
	
	public boolean getTopMenu(){
		String value = getValue(GlobalSetting.TOP_MENU, Boolean.FALSE.toString());
		return Boolean.valueOf(value);
	}
	
	void setTopMenu(Boolean topMenu){
		if (topMenu == null){
			topMenu = Boolean.FALSE;
		}
		setValue(GlobalSetting.TOP_MENU, topMenu.toString());
	}
	
	public Boolean getStartDelivery(){
		String value = getValue(GlobalSetting.START_DELIVERY, Boolean.FALSE.toString());
		return Boolean.valueOf(value);
	}
	
	void setStartDelivery(Boolean startDelivery){
		if (startDelivery == null){
			startDelivery = Boolean.FALSE;
		}
		setValue(GlobalSetting.START_DELIVERY, startDelivery.toString());
	}
	
	public Boolean getDeliveryNotify(){
		String value = getValue(GlobalSetting.DELIVERY_NOTIFY, Boolean.FALSE.toString());
		return Boolean.valueOf(value);
	}
	
	public void setDeliveryNotify(Boolean deliveryNotify){
		if (deliveryNotify == null){
			deliveryNotify = Boolean.FALSE;
		}
		setValue(GlobalSetting.DELIVERY_NOTIFY, deliveryNotify.toString());
	}
	
	public Boolean getIncludeEnterpriseBehalf(){
		String value = getValue(GlobalSetting.INCLUDE_ENTERPRISE_BEHALF, Boolean.FALSE.toString());
		return Boolean.valueOf(value);
	}
	
	public void setIncludeEnterpriseBehalf(Boolean includeEnterpriseBehalf){
		if (includeEnterpriseBehalf == null){
			includeEnterpriseBehalf = Boolean.FALSE;
		}
		setValue(GlobalSetting.INCLUDE_ENTERPRISE_BEHALF, includeEnterpriseBehalf.toString());
	}
	
	public Boolean getIncludePPV(){
		String value = getValue(GlobalSetting.INCLUDE_PPV, Boolean.FALSE.toString());
		return Boolean.valueOf(value);
	}
	
	public void setIncludePPV(Boolean includePPV){
		if (includePPV == null){
			includePPV = Boolean.FALSE;
		}
		setValue(GlobalSetting.INCLUDE_PPV, includePPV.toString());
	}
	
	public Boolean getUnifyPartItemCode(){
		String value = getValue(GlobalSetting.UNIFY_PARTITEMCODE, Boolean.TRUE.toString());
		return Boolean.valueOf(value);
	}
	
	public void setUnifyPartItemCode(Boolean unifyPartItemCode){
		if (unifyPartItemCode == null){
			unifyPartItemCode = Boolean.TRUE;
		}
		setValue(GlobalSetting.UNIFY_PARTITEMCODE, unifyPartItemCode.toString());
	}
	
	public Boolean getIncludeItemAllocateAndPurchasingItem(){
		String value = getValue(GlobalSetting.INCLUDE_ITEMALLOCATE_AND_PURCHASINGITEM, Boolean.FALSE.toString());
		return Boolean.valueOf(value);
	}
	
	public void setIncludeItemAllocateAndPurchasingItem(Boolean includeItemAllocateAndPurchasingItem){
		if (includeItemAllocateAndPurchasingItem == null){
			includeItemAllocateAndPurchasingItem = Boolean.FALSE;
		}
		setValue(GlobalSetting.INCLUDE_ITEMALLOCATE_AND_PURCHASINGITEM, includeItemAllocateAndPurchasingItem.toString());
	}
	private static final String SYSTEMSETTING = "SystemSetting";
	public SystemSetting getSystemSetting(){
		SystemSetting systemSetting = systemSettingCache.get(SYSTEMSETTING);
		if (systemSetting == null){
			systemSetting = genericService.searchAll(new SystemSetting()).getData(0);
			if (systemSetting == null) {
				logger.warn("No system setting found, use empty setting temporarily");
				systemSetting = new SystemSetting();
			}
			systemSettingCache.put(SYSTEMSETTING, systemSetting);
		}
		return systemSetting;
	}
	
	@Transactional
	public void _update(@ParamScope(value="#fn.newModel()") SystemSetting model,@ParamScope(visible=false, value="#ps")PageElements ps) {
		ps.setElementVisible("model.reportSetting.reportFileType.id", false);
		ps.setElementVisible("model.reportSetting.logo", false);
		
		SystemSetting systemSetting = getSystemSetting();
		if (systemSetting != null) {
			ModelUtil.copy(systemSetting, model);
			String rfqItems = systemSetting.safeGlobalSetting().getRfqSubscribeItems();
			if (rfqItems != null){
				String[] items = rfqItems.split(",");
				systemSetting.safeGlobalSetting().setAutoRfqSubscribeItems(items);
			}
			
			String publishItems = systemSetting.safeGlobalSetting().getPublishToRfqItems();
			if (publishItems != null){
				String[] items = publishItems.split(",");
				systemSetting.safeGlobalSetting().setAutoPublishToRfqItems(items);
			}
		}
	
		model.safeGlobalSetting().setAmountScale(getAmountScale());
		model.safeGlobalSetting().setPriceScale(getPriceScale());
		model.safeGlobalSetting().setDateFormat(getDateFormat());
		model.safeGlobalSetting().setPageSize(getPageSize());
		model.safeGlobalSetting().setAutoGoNext(getAutoGoNext());
		
	}
	
	public Result update(SystemSetting model) {
		if (model != null && model.getGlobalSetting() != null){
			if (model.getGlobalSetting().getAutoRfqSubscribeItems() != null){
				String subscribes = "";
				for(String subscribe : model.getGlobalSetting().getAutoRfqSubscribeItems()){
					subscribes +=  subscribe + ",";
				}
				model.getGlobalSetting().setRfqSubscribeItems(subscribes);
			}
			
			if (model.getGlobalSetting().getAutoPublishToRfqItems() != null){
				String subscribes = "";
				for(String subscribe : model.getGlobalSetting().getAutoPublishToRfqItems()){
					subscribes +=  subscribe + ",";
				}
				model.getGlobalSetting().setPublishToRfqItems(subscribes);
			}
		}
		if (model.getPrintTemplate() != null){
			for(RelatedFile file : model.getPrintTemplate()){
				file.setSystemSetting(model);
			}
		}
		uploadFileService.setFiles(model.getClass(), model.getPrintTemplate() ,null);
		
		model = genericService.merge(model);

		String url = urlUtil.getUrl(SystemSetting.class, "_update", null);
		Result result = new ServletActionRedirectResult(url);
		objectFactory.autoWireBean(result);
		
		ognlExUtil.getOgnlUtil().copy(model, config, BlankObject.Map);
		
		systemSettingCache.clear();
		globalSettingCache.clear();
		
		setAmountScale(getSystemSetting().safeGlobalSetting().getAmountScale());
		setAutoGoNext(getSystemSetting().safeGlobalSetting().getAutoGoNext());
		setDateFormat(getSystemSetting().safeGlobalSetting().getDateFormat());;
		setPageSize(getSystemSetting().safeGlobalSetting().getPageSize());
		setPriceScale(getSystemSetting().safeGlobalSetting().getPriceScale());
		setStartDelivery(getSystemSetting().safeGlobalSetting().getStartDelivery());
		setTopMenu(getSystemSetting().safeGlobalSetting().getTopMenu());
		
		return result;
	}
	
	private void cleanCache(){
		systemSettingCache.clear();
		globalSettingCache.clear();
	}
	
	public void initData(){
		SystemSetting model = getSystemSetting();
		if (model == null){
			model = new SystemSetting();
			model.safeGlobalSetting().setStartWorkFlow(true);
			model = genericService.add(model);
		}
		
		List<RelatedFile> relatedFiles = model.getPrintTemplate();
		if (relatedFiles == null || relatedFiles.isEmpty()){
			relatedFiles = new ArrayList<RelatedFile>();
			relatedFiles.add(addRelatedFile("Quote Template", "Quote.xls"));
			relatedFiles.add(addRelatedFile("Purchase Order Template", "PurchaseOrder.xls"));
			relatedFiles.add(addRelatedFile("Sales Order Template", "SalesOrder.xls"));
			relatedFiles.add(addRelatedFile("Packing List Template", "PackingList.xls"));
			for(RelatedFile relatedFile : relatedFiles){
				relatedFile.setSystemSetting(model);
			}
			model.setPrintTemplate(relatedFiles);
			genericService.merge(getSystemSetting());
		}
		
		
		if (systemDataService.getValue(SystemData.START_YEAR) == null){
			String year = new SimpleDateFormat("yyyy").format(new Date());
			systemDataService.setValue(SystemData.START_YEAR, year);
		}
	}
	private RelatedFile addRelatedFile(String remark , String fileName){
		String path = config.getUploadDir() + "SystemSetting/" + fileName;
		RelatedFile result = new RelatedFile();
		result.setFileFileName(path);
		result.setRemark(remark);
		return result;
	}
}

